#include "common.h"
#include "stru_queue.h"
#include "thread.h"
pthread_mutex_t lock_malloc_t;         
void test_queue_main()
{
    LOG_DEBUG("-------------------test queue start--------------- \n");
    BQueueBox *bQueBox = createBQueue(DATA_PCIE_BUFF_SIZE, PCIE_QUEUE_NUM, PCIE_QUEUE_EXTEN);
    LOG_DEBUG("queue len: %d \n", verifyQBoxLen(bQueBox));

    destroyBQueue(bQueBox);
    LOG_DEBUG("------------------- test queue end --------------- \n");
    return ;
}

/***********************************无序队列************************************/
/***
 * @param bsize rbuf 的缓冲区域, @param bNum 初始化个数 @param exNum 扩容的个数
 */
BQueueBox *createBQueue(int bsize, int bNum, int exNUM)
{
    int boxlen = sizeof(BQueueBox);
    BQueueBox *bQBox = (BQueueBox *)malloc(boxlen);
    LOG_EXAM_TEST("---> 申请: %p, [bQBox] \n", bQBox);
    memset((void *)bQBox, 0x00, boxlen);
    bQBox->bNum = bNum;
    bQBox->exNum = exNUM;
    bQBox->blen = bsize;
    int bqlen = sizeof(BQueue) * bNum;
    BQueue *bQue = (BQueue *)malloc(bqlen);
    LOG_EXAM_TEST("---> 申请: %p, [bQue] \n", bQue);
    memset((void *)bQue, 0x00, bqlen);
    bQBox->bQueue = bQue;                   //记录头指针
    BQueue *cbQue = NULL;

    while ((bNum--) > 0)
    {
        bQue->blen = bsize;
        bQue->flag = QU_FREE;               //空闲状态
        bQue->rbuf = (uint8 *)malloc(bQue->blen);
        LOG_EXAM_TEST("---> 申请: %p, [bQue->rbuf] \n", bQue->rbuf);
        memset((void *)bQue->rbuf, 0x00, bQue->blen);
        if (NULL != cbQue)
        {
            cbQue->next = bQue;
        }
        cbQue = bQue;
#ifdef QUEUE_DEBUG
        LOG_INFO("bqueue 地址: %p, buff 地址: %p \n", bQue, bQue->rbuf);
#endif
        *bQue++;
    }
    return bQBox;
}

/** 验证 Bqueue 是否正确 **/
int verifyQBoxLen(BQueueBox *bQuBox)
{
    BQueue *queue = bQuBox->bQueue;

    int i = 0;
    while (queue != NULL)
    {
        LOG_DEBUG("queue->blen: %d \n", queue->blen);
        LOG_DEBUG("queue->channel: %d  \n", queue->channel);
        LOG_DEBUG("queue->flag: %d \n", queue->flag);
        queue = queue->next;
        i++;
    }
    return i;
}

/** 申请一块闲置的内存 **/
BQueue * mallocBQueue(BQueueBox *bQuBox)
{
    SCMutexLock(&lock_malloc_t);
    BQueue *queue = bQuBox->bQueue;
    while (queue != NULL)
    {
        if(queue->flag == QU_FREE){
            queue->flag = QU_BUSY;
            SCMutexUnlock(&lock_malloc_t);
            return queue;
        }
        queue = queue->next;
    }
    /** 先测试基本的队列, 看下性能, 后期可以做扩容 */
    // LOG_DEBUG("#ERR: 数据队列已满, 没有闲置的内存队列可用 \n");
    SCMutexUnlock(&lock_malloc_t);
    return NULL;
}

/** 回收内存到队列中 */
pthread_mutex_t lock_free_t;
BQueue * freeBQueue(BQueue * bQueue) {
    // SCMutexLock(&bQuBox->lock_free_t);
    SCMutexLock(&lock_free_t);
    bQueue->flag = QU_FREE;
    // memset(bQueue, 0x00, bQueue->blen);
    SCMutexUnlock(&lock_free_t);
    // SCMutexUnlock(&bQuBox->lock_free_t);
}
extern int thread_recv_pcie_signal;
/** 程序结束的时候释放内存, 即销毁内存 **/
int destroyBQueue(BQueueBox * bQueBox) {
    //首先检测程序中是否还存在 QU_BUSY 的队列
    int num = 0;
    while ((num = getBusyNumBQueue(bQueBox->bQueue))) 
    {
#ifdef  QUEUE_STATUS
        LOG_INFO("#ERR: err to destory queue, exitNum is %d \n", num);
#endif
        if(!thread_recv_pcie_signal) break;
        
    }

    /** 销毁内存 */
    BQueue *queue = bQueBox->bQueue;

    while (queue != NULL)
    {
        LOG_EXAM_TEST("---> 释放: %p, [queue->rbuf] \n", queue->rbuf);
        free((void *)queue->rbuf);
        queue->rbuf = NULL;
        queue = queue->next;
    }
    LOG_EXAM_TEST("---> 释放: %p, [bQueBox->bQueue] \n", bQueBox->bQueue);
    free((void *)bQueBox->bQueue);
    bQueBox->bQueue = NULL;
    LOG_EXAM_TEST("---> 释放: %p, [bQueBox] \n", bQueBox);
    free((void *)bQueBox);
    bQueBox = NULL;
    return KT_OK;
}

/** 检测程序是否含有 QU_BUSY 的队列, 并返回当前存在的个数 */
int getBusyNumBQueue(BQueue * queue) {
    int num = 0;
    while (queue != NULL)
    {   
        if(queue->flag == QU_BUSY) {
            // LOG_DEBUG("queue: %p, channel: %d \n", queue, queue->channel);
            num++;
        }
        queue = queue->next;
    }
    return num;
}

/*********************************FIFO队列**************************************/
void test_queue_del_order_queue(OrderQueueBox *oqBox) {  //使用线程测试
    verifyOrderQueue(oqBox, 16);
    int num;
    while (0 != (num = getUsedNumOrderBQue(oqBox))) {
        outputOrderQueueEle(oqBox);
        LOG_DEBUG("还有 %d 个数据未从队列中取出 \n", (num - 1));
    }
    LOG_DEBUG("已从队列中将数据取完 \n");
    verifyOrderQueue(oqBox, 16);
}

void test_queue_FIFO() {
    OrderQueueBox *oqBox = createOrderQueue(15);
    LOG_DEBUG("num: %d \n", getUsedNumOrderBQue(oqBox));
    BQueue queue[15];
    size_t i = 0;
    for (; i < 15; i++)
    {
        inputOrderQueueEle(oqBox, &queue[i]);
    }
    LOG_DEBUG("num: %d \n", getUsedNumOrderBQue(oqBox));
    // inputOrderQueueEle(&oqBox, &queue[0]);
    // verifyOrderQueue(&oqBox, 16);
    outputOrderQueueEle(oqBox);
    LOG_DEBUG("num: %d \n", getUsedNumOrderBQue(oqBox));

    outputOrderQueueEle(oqBox);
    LOG_DEBUG("num: %d \n", getUsedNumOrderBQue(oqBox));

    outputOrderQueueEle(oqBox);
    LOG_DEBUG("num: %d \n", getUsedNumOrderBQue(oqBox));

    verifyOrderQueue(oqBox, 16);

    pthread_t cc_id;
    pthread_create(&cc_id, NULL, test_queue_del_order_queue,(void *)oqBox);

    //销毁队列
    if(destoryOrderQueue(oqBox) == KT_OK) {
        LOG_DEBUG("释放队列成功! \n");
    }
}


/** 
 * @param oqBox 环形队列    @param num 创建的队列长度/个数
 */
OrderQueueBox * createOrderQueue(int num) {
    OrderQueueBox *oqBox = (OrderQueueBox *)malloc(sizeof(oqBox));
    LOG_EXAM_TEST("---> 申请: %p, [oqBox] \n", oqBox);
    int size = sizeof(OrderQueue) * (num + 1);  // +1 ?
    OrderQueue *queue = (struct OrderQueue *) malloc(size); 
    LOG_EXAM_TEST("---> 申请: %p, [queue] \n", queue);
    memset((void *)queue,0x00,size);
    oqBox->flag = queue;
    oqBox->head = queue;
    oqBox->end = queue;
    OrderQueue * curQueue = NULL; 
    num += 1;
    while ((num--) > 0) {
        queue->data = NULL;
        if(NULL != curQueue) {
            curQueue->next = queue;
        }
        curQueue = queue;
        *queue++;
    }
    curQueue->next = oqBox->head;
    return oqBox;
}

//进队列
int inputOrderQueueEle(OrderQueueBox *orderQBox, BQueue *bQueue) {
    //看队列是否已满
    if(orderQBox->end->next == orderQBox->head) {
        LOG_ERROR("当前队列已满, %p \n", orderQBox);
        return KT_ERROR;
    }
    orderQBox->end->data = bQueue;
    orderQBox->end = orderQBox->end->next;
    return KT_OK;
}

//出队列
BQueue *outputOrderQueueEle(OrderQueueBox *orderQBox) {
    //查看队列是否有为NULL
    if(orderQBox->head == orderQBox->end) {
        // LOG_ERROR("当前队列为NULL, %p \n", orderQBox);
        return NULL;
    }
    BQueue *curQueue = orderQBox->head->data;
    orderQBox->head->data = NULL;
    orderQBox->head = orderQBox->head->next;
    return curQueue;
}

//释放队列
int destoryOrderQueue(OrderQueueBox *oqBox) {
    int num;
    while ((num = getUsedNumOrderBQue(oqBox)) != 0) {
// #ifdef  QUEUE_STATUS
        LOG_WARN("有序队列 %p, 还有 %d 个数据块正在使用中 \n", oqBox, num);
// #endif
        if(!thread_recv_pcie_signal) break;
    }
    LOG_EXAM_TEST("---> 释放: %p, [oqBox->flag] \n", oqBox->flag);
    free(oqBox->flag);
    oqBox->flag = NULL;
    oqBox->head = NULL;
    oqBox->end = NULL;
    LOG_EXAM_TEST("---> 释放: %p, [oqBox] \n", oqBox);
    free(oqBox);
    oqBox = NULL;
    return KT_OK;
}

//获取队列为used的数量
int getUsedNumOrderBQue(OrderQueueBox *oqBox) {
    OrderQueue *oqueue = oqBox->head; 
    int num = 0;
    while (oqueue != oqBox->end) {
        // LOG_DEBUG("oqBox->end: %p \n", oqBox->end);
        oqueue = oqueue->next;
        num++;
        if(num > 4000) {
            LOG_ERROR("#ERR: 防止程序出错检查, 大于4000时退出程序 \n");
            exit(0);
            break;
        }
    }
    return num;
}
//验证有序队列
void verifyOrderQueue(OrderQueueBox *oqBox, int times) {
    LOG_DEBUG("head: %p, end: %p, flag: %p,\n", oqBox->head, oqBox->end, oqBox->flag);
    OrderQueue *queue = oqBox->head;
    int i = 0;
    while (i < times)
    {
        LOG_DEBUG("queue: %p, queue->data: %p \n", queue, queue->data);
        queue=queue->next;
        i++;
    }
}